/* lcn/lcn.c 
 * 
 * This file is part of lcn. 
 * 
 * lcn is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version. 
 * 
 * lcn is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with lcn. If not, see <https://www.gnu.org/licenses/>
 */ 




#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <locale.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/mman.h>

#include <lcn/lcn.h>

extern int fd;
int load_article(char *name, char **dst);
int open_editor(char *p);
char *request_list(void);

int lcn_read_article(char *name) {
	char 	*buf;
	int 	fdt;
	int 	size;

	if (unlikely((size = load_article(name, &buf)) < 0)) {
		fprintf(stderr, "%s: %s\n", name, strerror(-size));

		return size;
	}

	/* yeah, i know 'tmpnam' is not good, but i can't find 
	 * a simple way to get the name of a FILE * or of a fd. 
	 * so just use it, execuse me. */

#if 0
	fdt = fileno(tmpfile());
#endif

	/* okay, okay, the ****ing ld is warning me. so let's use 
	 * a fixed name.  */

#if 0
	p = tmpnam(NULL);
#endif
	if (unlikely((fdt = open("/tmp/lcn-tmp-article", O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0)) {
		perror("open");

		return 1;
	}

	write(fdt, buf, size);
	close(fdt);

	if (unlikely(open_editor("/tmp/lcn-tmp-article"))) {
		fprintf(stderr, "unable to open the editor. \n");

		return 1;
	}

	return 0;
}

int lcn_list_articles(void) {
	request_list();

	return 0;
}


/* we have to do this... change it later */

int read_string(int fd, char *buf, int max) {
	int i;

	for (i = 0; i < max; i++) {
		read(fd, buf + i, 1);

		if (!buf[i]) 
			return i;
	}

	buf[max - 1] = 0;
	return i;
}


char *request_list(void) {
	char 	response[8];
	char 	buf[128];
	int 	total;

	write(fd, "list", 4);
	read(fd, response, 8);

	sscanf(response, "%08d", &total);
	printf("%d articles. \n", total);

	while (total--) {
		read_string(fd, buf, 128);
		printf("%s\n", buf);
	}

	return NULL;
}


int load_article(char *name, char **dst) {
	char 	*p, *buf;
	char 	response[8];
	int 	len;
	int 	size, did_read = 0;

	len = strlen(name) + 1;

	if (unlikely(!(p = malloc(len)))) 
		return -ENOMEM;

	memcpy(p, "read", 4);
	strcpy(p + 4, name);

	write(fd, p, len + 4);
	read(fd, response, 4);

	if (strncmp(response, "E200", 4)) 
		return -ENOENT;

	read(fd, response, 8);
	sscanf(response, "%08d", &size);

	if (unlikely((buf = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) == MAP_FAILED)) 
		return -ENOMEM;

	/* so the server must write() as only one operation */
	while ((did_read += read(fd, buf + did_read, size)) < size) 
		;

	*dst = buf;

	return size;
}


int try_editor(char *editor, char *fp) {
	int pid, code;

	if (!(pid = fork())) {
		execlp(editor, editor, fp, NULL);
		perror("execve");

		exit(ENOENT);
	}

	waitpid(pid, &code, 0);
	return code;
}


int open_editor(char *fp) {
	if (try_editor("vim", fp) && 
			try_editor("vi", fp) && 
			try_editor("nano", fp) && 
			try_editor("emacs", fp) && 
			try_editor("less", fp) && 
			try_editor("more", fp)) {
		fprintf(stderr, "****, that's impossible. \n");

		return 1;
	}

	return 0;
}


